home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / contrib / russo / gnuplotio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-25  |  11.8 KB  |  533 lines

  1. /*
  2.  *  Gnuplotio - A procedural interface to Gnuplot which turns
  3.  *        Gnuplot into an expression evaluator.
  4.  *
  5.  *  NOTE: gnuplot (verision 3.0 or higher) must have the "table" terminal type.
  6.  *
  7.  *  Written by Kevin Russo   SFA, Inc/US Naval Research Lab, Code 5133
  8.  *                           March 1991
  9.  *
  10.  *  Future fix: all reads should be non-blocking and return the number
  11.  *  of chars read.
  12.  */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <errno.h>
  17. #ifdef MSDOS
  18. #include <io.h>    /* access */
  19. #include <sys\types.h>
  20. #else
  21. #include <unistd.h>    /* access */
  22. #include <sys/types.h>
  23. #endif
  24. #include "gnuplotio.h"
  25. #include "popen.h"
  26. #include "util.h"
  27.  
  28. /*
  29.  * openGnuplot(NULL)
  30.  * openGnuplot("")
  31.  *    Searches your $PATH for "gnuplot"
  32.  *
  33.  * openGnuplot("gnuplot3.1")
  34.  *    Searches your $PATH for "gnuplot3.1"
  35.  *
  36.  * openGnuplot("/obscure/gnuplot")
  37.  *    Runs /obscure/gnuplot if it exists and is executable
  38.  * 
  39.  * open 3 pipes to a gnuplot process. (stdin, stdout, stderr)
  40.  *
  41.  *     popen_ioe() is like popen(3) but it opens 3 pipes.
  42.  *
  43.  * Returns:
  44.  *    GNUPLOT handle
  45.  */
  46. GNUPLOT *openGnuplot(const char *gnuplotpath)
  47. {
  48. GNUPLOT *gp;
  49. char *programpath;
  50.  
  51.     /* This code guarantees that popen_ioe() can't fail...
  52.        there's no good way to recover from popen() failing
  53.     */
  54.     if (gnuplotpath == NULL || *gnuplotpath == '\0')
  55.     {   /* see if popen("gnuplot") will work */
  56.         programpath = "gnuplot";
  57.         switch (can_run(programpath))
  58.         {
  59.         case 1:
  60.         fprintf(stderr,"openGnuplot: %s is not executable\n",
  61.            programpath);
  62.         return NULL;
  63.         /* NOTREACHED */
  64.         break;
  65.         case 2:
  66.         fprintf(stderr,"openGnuplot: %s is not in $path\n",programpath);
  67.         return NULL;
  68.         /* NOTREACHED */
  69.         break;
  70.         }
  71.     }
  72.     else if (strchr(gnuplotpath, '/') == NULL)
  73.     {   /* see if popen(other_gnuplot_in_search_path) will work */
  74.         programpath = gnuplotpath;
  75.         switch (can_run(programpath))
  76.         {
  77.         case 1:
  78.         fprintf(stderr,"openGnuplot: %s is not executable\n",
  79.            programpath);
  80.         return NULL;
  81.         /* NOTREACHED */
  82.         break;
  83.         case 2:
  84.         fprintf(stderr,"openGnuplot: %s is not in $path\n",programpath);
  85.         return NULL;
  86.         /* NOTREACHED */
  87.         break;
  88.         }
  89.     }
  90.     else
  91.     {   /* see if we can execute the path-qualified (ie has /) */
  92.         programpath = gnuplotpath;
  93.         if (access(programpath, X_OK) == -1)
  94.         {
  95.         fprintf(stderr,"openGnuplot: can't execute %s.  Reason: %s\n",
  96.         programpath, strerror(errno));
  97.         return NULL;
  98.         }
  99.     }
  100.  
  101.     if ((gp = (GNUPLOT *) malloc(1 * sizeof(GNUPLOT))) == NULL)
  102.     {
  103.         fprintf(stderr,"openGnuplot: malloc failure.\n");
  104.         return NULL;
  105.     }
  106. /*
  107.     if((gp->ptr = popen_ioe(programpath,"rwe")) == NULL) */
  108.     if((gp->ptr = popen_rw(programpath)) == NULL)
  109.     {
  110.         /* can_run() above should catch any failure, so this
  111.            shouldn't ever happen (famous last words) */
  112.         fprintf(stderr,"openGnuplot: can't popen_ioe() to %s\n",
  113.            programpath);
  114.         return NULL;
  115.     }
  116.  
  117.     setbuf(gp->ptr[1], (char *)0);    /* no buffering on writes */
  118. /*    setbuf(gp->ptr[2], (char *)0);    /* no buffering on stderr reads */
  119.     return gp;
  120. }
  121.  
  122.  
  123.  
  124. /*
  125.  * Write a command to the gnuplot process
  126.  *
  127.  * Returns:
  128.  *    0 if any input arguments were invalid
  129.  *    1 presume success writing to gnuplot
  130.  */
  131. int writeGnuplot(GNUPLOT *gp, const char *command)
  132. {
  133. size_t len;
  134. char *cmd;
  135. #ifdef ACK_WORKING
  136. char ack[20];
  137. #endif /* ACK_WORKING */
  138.  
  139.     if (gp != NULL && gp->ptr[1] != NULL && command != NULL)
  140.     {
  141.         len = strlen(command);
  142.         if (command[len-1] != '\n')
  143.         {
  144.             /* ensure that the command is new-line-terminated */
  145.             cmd = (char *) malloc(len+2);
  146.             strcpy(cmd, command);
  147.             cmd[len] = '\n';
  148.             cmd[len+1] = '\0';
  149.             fputs(cmd,gp->ptr[1]);
  150.             free(cmd);
  151.         }
  152.         else
  153.             fputs(command,gp->ptr[1]);
  154. #ifdef ACK_WORKING
  155.         /* block until gnuplot is finished */
  156.         fgets(ack, sizeof(ack), gp->ptr[2]);
  157.         printf("ack: \"%s\"\n",ack);
  158. #endif /* ACK_WORKING */
  159.  
  160.         return 1;
  161.     }
  162.  
  163.     return -1;
  164. }
  165.  
  166. /*
  167.  * There are several ways to retrieve results from gnuplot:
  168.  *
  169.  * readErrorGnuplot()
  170.  *
  171.  * readGnuplot()
  172.  *    returns a line of gnuplot output
  173.  *
  174.  * readCurveHeadGnuplot()
  175.  *    returns the curve number and number of points. Use after writing
  176.  *    a "plot" or "splot" command to gnuplot.
  177.  *
  178.  * readCurve2Gnuplot()
  179.  *    fills the x[points], y[points] arrays with the points of a "plot"
  180.  *    command. The function returns the actual number of points read
  181.  *    (which could differ from npoints)
  182.  *
  183.  * readCurve3Gnuplot()
  184.  *    fills the x[points], y[points] z[npoints] arrays with the points
  185.  *    of a "splot" command. The function returns the actual number of
  186.  *    points read (which could differ from npoints)
  187.  */
  188.  
  189.  
  190. /*
  191.  * readErrorGnuplot
  192.  *
  193.  * Returns:
  194.  *    Number of bytes copied to the read buffer or
  195.  *    -1 if any input parameters were invalid
  196.  *
  197.  * Side Effects:
  198.  *    readbuf is filled with the error message, to a maximum of
  199.  *    sizeofreadbuf chars.
  200.  *
  201.  */
  202.  
  203. int readErrorGnuplot(GNUPLOT *gp, char *readbuf, size_t sizeofreadbuf)
  204. {
  205. int n;
  206.     if (gp != NULL && gp->ptr[2] != NULL && readbuf != NULL)
  207.     {
  208.         /* we don't want to block on this attempted read! */
  209.         if (check_fd_for_reading(fileno(gp->ptr[2])))
  210.         {
  211.             /*printf("reading stderr\n");*/
  212.             /*fgets(readbuf, sizeofreadbuf, gp->ptr[2]);*/
  213.             /* unbuffered... get it all */
  214.             n=read(fileno(gp->ptr[2]), readbuf,sizeofreadbuf);
  215.             return n;
  216.         }
  217.         else
  218.             return 0;
  219.     }
  220.  
  221.     return -1;
  222. }
  223.  
  224.  
  225. /*
  226.  * readGnuplot
  227.  *
  228.  * Fills readbuf with one line from gnuplot
  229.  * This read blocks, so call it only when you expect some output
  230.  *
  231.  * Returns:
  232.  *    -1 if any input parameters were invalid
  233.  *    1 presumed success
  234.  *
  235.  */
  236. int readGnuplot(GNUPLOT *gp, char *readbuf, size_t sizeofreadbuf)
  237. {
  238.     if (gp != NULL && gp->ptr[0] != NULL && readbuf != NULL)
  239.     {
  240.         fgets(readbuf, sizeofreadbuf, gp->ptr[0]);
  241.         return 1;
  242.     }
  243.  
  244.     return -1;
  245. }
  246.  
  247.  
  248. /*
  249.  * readCurveHeadGnuplot
  250.  *
  251.  * After a 'plot' or 'splot' command id issued to gnuplot, it responds
  252.  * with a line containing the curve id # and the number of points (lines)
  253.  * in this curve.
  254.  *
  255.  * Side Effects:
  256.  *    The converted integers are returned in as a side effect.
  257.  *
  258.  * Returns:
  259.  *    -1 if any input parameters were invalid
  260.  *    1 presumed success
  261.  *
  262.  */
  263. int readCurveHeadGnuplot(GNUPLOT *gp, int *p_curveno, int *p_npts)
  264. {
  265. char buf[81];
  266.  
  267.     if (gp!=NULL && gp->ptr[0]!=NULL && p_curveno!=NULL && p_npts!=NULL)
  268.     {
  269.         /* this format should match what Gnuplot writes out */
  270.         /*fscanf(gp->ptr[0],"Curve %d, %d points\n",p_curveno,p_npts);*/
  271.         do
  272.             fgets(buf, sizeof(buf),gp->ptr[0]);
  273.         while (buf[0] == '\n');
  274.         sscanf(buf,"Curve %d, %d points\n",p_curveno,p_npts);
  275.  
  276.         return 1;
  277.     }
  278.  
  279.     return -1;
  280. }
  281.  
  282. #define FREEALL_AND_LEAVE() \
  283.     free((void*)r);free((void*)x);free((void*)y);free((void*)curve); \
  284.     return NULL
  285.  
  286. GPCurve *readCurveGnuplot(GNUPLOT *gp)
  287. {
  288. GPCurve *curve;
  289. int curveno, npts, cnt, i, is2d, n;
  290. char buf[81], *r;
  291. float *x,*y,*z;
  292.  
  293.     if (gp == NULL || gp->ptr[0] == NULL)
  294.         return NULL;
  295.  
  296.     if ((curve = (GPCurve *) calloc(1, sizeof(GPCurve))) == NULL)
  297.         return NULL;
  298.  
  299.     /* this format should match what Gnuplot writes out */
  300.     /*fscanf(gp->ptr[0],"Curve %d, %d points\n",&curveno,&npts);*/
  301.     do
  302.         fgets(buf, sizeof(buf),gp->ptr[0]);
  303.     while (buf[0] == '\n');
  304.  
  305.     sscanf(buf,"Curve %d, %d points\n",&curveno,&npts);
  306.     if (npts < 1)
  307.     {
  308.         free((void *) curve);
  309.         return NULL;
  310.     }
  311.  
  312.     curve->curveno = curveno;
  313.     curve->range = r = (char *) malloc(npts * sizeof(char));
  314.     if (r == NULL)
  315.     {
  316.         free((void *) curve);
  317.         return NULL;
  318.     }
  319.     curve->x = x = (float *) malloc(npts * sizeof(float));
  320.     if (x == NULL)
  321.     {
  322.         free((void *) curve);
  323.         free((void *) r);
  324.         return NULL;
  325.     }
  326.     curve->y = y = (float *) malloc(npts * sizeof(float));
  327.     if (y == NULL)
  328.     {
  329.         free((void *) curve);
  330.         free((void *) r);
  331.         free((void *) x);
  332.         return NULL;
  333.     }
  334.     
  335.     /* read the first line to see how many columns */
  336.     fgets(buf, sizeof(buf), gp->ptr[0]);
  337.     if ((n=count_items(buf)) == 4)
  338.     {
  339.         curve->is_2d = is2d = FALSE;
  340.         curve->z = z = (float *) malloc(npts * sizeof(float));
  341.         if (z == NULL)
  342.         { FREEALL_AND_LEAVE(); }
  343.             sscanf(buf,"%c x=%g y=%g z=%g\n",&r[0],&x[0],&y[0],&z[0]);
  344.     }
  345.     else if (n == 3)
  346.     {
  347.         curve->is_2d = TRUE;
  348.         curve->z = NULL;
  349.             sscanf(buf,"%c x=%g y=%g\n",&r[0],&x[0],&y[0]);
  350.     }
  351.     else
  352.     {
  353.         /* this shouldn't happen */
  354.         fprintf(stderr,"readCurveGnuplot: count_items() not 3 or 4 "
  355.         "(n=%d)\n", n);
  356.         return NULL;
  357.     }
  358.     cnt = 1;
  359.         for (i=1; i<npts && *buf != '\0'; i++)
  360.         {
  361.         fgets(buf, sizeof(buf), gp->ptr[0]);
  362.         if(*buf != '\n' && *buf != '\0')
  363.         {
  364.         if (is2d) sscanf(buf,"%c x=%g y=%g\n",&r[i],&x[i],&y[i]);
  365.         else sscanf(buf,"%c x=%g y=%g z=%g\n",&r[i],&x[i],&y[i],&z[i]);
  366.             cnt++;
  367.         }
  368.     }
  369.     curve->npts = cnt;    /* _should_ equal npts! */
  370.     return curve;
  371. }
  372.  
  373.  
  374.  
  375. /*
  376.  * readCurve2Gnuplot
  377.  *
  378.  * After a 'plot' command has been written and the curve heading read
  379.  * back, this routine will convert all the points in the curve and
  380.  * store them in the user's buffers.
  381.  *
  382.  * Inputs:
  383.  *    x[], y[] and range[] must be dimensioned to at least npoints!
  384.  *    range[] is a char buffer that contains on of:
  385.  *
  386.  *        i - INRANGE, inside plot boundary
  387.  *        o - OUTRANGE, outside plot boundary, but defined
  388.  *        u - UNDEFINED, not defined at all
  389.  *
  390.  *    range[] is optional; pass a NULL pointer if you don't want it.
  391.  * 
  392.  * Returns:
  393.  *    Number of points converted and stored in x,y,range or
  394.  *    -1 if any input parameters were invalid
  395.  *
  396.  *
  397.  */
  398. int readCurve2Gnuplot(GNUPLOT *gp, char *range, float *x, float *y, int npoints)
  399. {
  400. register int i;
  401. int cnt;
  402. char buf[81], c;
  403.  
  404.     if (gp != NULL && gp->ptr[0] != NULL && x != NULL && y != NULL)
  405.     {
  406.         cnt = 0;
  407.  
  408.         if (range != NULL)
  409.         {
  410.             for (i=0; i<npoints; i++)
  411.             {
  412.             fgets(buf, sizeof(buf), gp->ptr[0]);
  413.             if(*buf != '\n' && *buf != '\0')
  414.             {
  415.                 sscanf(buf,"%c x=%g y=%g\n",&range[i],&x[i],&y[i]);
  416.                 cnt++;
  417.             }
  418.             }
  419.         }
  420.         else        /* throw range away */
  421.         {
  422.             for (i=0; i<npoints; i++)
  423.             {
  424.             fgets(buf, sizeof(buf), gp->ptr[0]);
  425.             if(*buf != '\n' && *buf != '\0')
  426.             {
  427.                 sscanf(buf,"%c x=%g y=%g\n",&c,&x[i],&y[i]);
  428.                 cnt++;
  429.             }
  430.             }
  431.         }
  432.         return cnt;
  433.     }
  434.  
  435.     return -1;
  436. }
  437.  
  438.  
  439.  
  440. /*
  441.  * readCurve3Gnuplot
  442.  *
  443.  * After an 'splot' command has been written and the curve heading read
  444.  * back, this routine will convert all the points in the curve and
  445.  * store them in the user's buffers.
  446.  *
  447.  * Inputs:
  448.  *    x[], y[], z[] and range[] must be dimensioned to at least npoints!
  449.  *    range[] is a char buffer that contains on of:
  450.  *
  451.  *        i - INRANGE, inside plot boundary
  452.  *        o - OUTRANGE, outside plot boundary, but defined
  453.  *        u - UNDEFINED, not defined at all
  454.  *
  455.  *    range[] is optional; pass a NULL pointer if you don't want it.
  456.  * 
  457.  * Returns:
  458.  *    Number of points converted and stored in x,y,range or
  459.  *    -1 if any input parameters were invalid
  460.  *
  461.  *
  462.  */
  463. int readCurve3Gnuplot(GNUPLOT *gp, char *range, float *x, float *y, float *z,
  464.             int npoints)
  465. {
  466. register int i;
  467. int cnt;
  468. char buf[81], c;
  469.  
  470.     if (gp != NULL && gp->ptr[0] != NULL && x != NULL && y != NULL &&
  471.         z != NULL)
  472.     {
  473.         cnt = 0;
  474.  
  475.         if (range != NULL)
  476.         {
  477.             for (i=0; i<npoints; i++)
  478.             {
  479.             fgets(buf, sizeof(buf), gp->ptr[0]);
  480.             if(*buf != '\n' && *buf != '\0')
  481.             {
  482.                 sscanf(buf,"%c x=%g y=%g\n",&range[i],&x[i],&y[i],
  483.                &z[i]);
  484.                 cnt++;
  485.             }
  486.             }
  487.         }
  488.         else        /* throw range away */
  489.         {
  490.             for (i=0; i<npoints; i++)
  491.             {
  492.             fgets(buf, sizeof(buf), gp->ptr[0]);
  493.             if(*buf != '\n' && *buf != '\0')
  494.             {
  495.                 sscanf(buf,"%c x=%g y=%g\n",&c,&x[i],&y[i],&z[i]);
  496.                 cnt++;
  497.             }
  498.             }
  499.         }
  500.         return cnt;
  501.     }
  502.  
  503.     return -1;
  504. }
  505.  
  506.  
  507.  
  508. /*
  509.  * closeGnuplot
  510.  *
  511.  * Shuts down the pipes to the gnuplot process.
  512.  * If quitflag is non-zero, a 'quit' command will be issued to gnuplot.
  513.  * 
  514.  * Returns:
  515.  *    1 presumed success at closing the connection
  516.  *    0 error in pclose_ioe()
  517.  *    -1 if any input parameters were invalid
  518.  *
  519.  */
  520. int closeGnuplot(GNUPLOT *gp, int quitflag)
  521. {
  522.     if (gp != NULL && gp->ptr[1] != NULL)
  523.     {
  524.         if (quitflag) fputs("quit\n",gp->ptr[1]);
  525.         if(pclose_ioe(gp->ptr) == -1)
  526.             return 0;
  527.         return 1;
  528.     }
  529.  
  530.     return -1;
  531. }
  532.  
  533.